package com.flute.framework.search;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Searcher;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;

import com.flute.framework.configuration.SearchInformation;
import com.flute.framework.exception.SearchException;
import com.flute.framework.index.IDocumentBuilder;
import com.flute.framework.search.result.MarkedResultProperty;
import com.flute.framework.search.result.ResultInfo;
import com.flute.framework.search.result.SearchResult;
import com.flute.framework.search.strategy.ISearchStrategy;
import com.flute.framework.search.strategy.SameSearchStrategy;
import com.flute.tools.util.ExceptionUtil;

public class LuceneSearcher implements ISearcher {
	private String searchName;
	private ISearcherProvider provider;
	private SearchInformation info;

	public LuceneSearcher() {
		this.info = new SearchInformation();
	}

	public SearchInformation getInfo() {
		return info;
	}

	public void setInfo(SearchInformation info) {
		this.info = info;
	}

	@Override
	public String search(SearchRequest request) throws SearchException {
		return info.getParser().parse(request, nakeSearch(request));
	}

	private List<ResultInfo> getResultInfoList(int start, int end,
			ScoreDoc[] sds, Searcher searcher, String keyword)
			throws SearchException {
		List<ResultInfo> list = new ArrayList<ResultInfo>();
		for (int i = start; i < end; i++) {
			ResultInfo resultInfo = new ResultInfo();
			try {
				for (MarkedResultProperty mrp : info.getParser()
						.getMarkedProperties()) {
					if (!mrp.getName().equals(ISearcher.SCORE)
							&& !mrp.getName().equals(ISearcher.DOC_ID)) {
						Document doc = searcher.doc(sds[i].doc);
						if (doc.getField(mrp.getName()) == null) {
							throw new SearchException("在文档中没有域：'"
									+ mrp.getName() + "'", "");
						}
						String value = doc.getField(mrp.getName())
								.stringValue();
						if (mrp.getMarker() != null) {
							value = mrp.getMarker().getMarkString(keyword,
									value);
						}
						resultInfo.addProperty(mrp.getName(), value);
					}
				}
			} catch (CorruptIndexException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			resultInfo.addProperty(SCORE, String.valueOf(sds[i].score));
			resultInfo.addProperty(DOC_ID, String.valueOf(sds[i].doc));

			list.add(resultInfo);
		}

		return list;
	}

	/**
	 * 生成过滤器对应的Query
	 * 
	 * @param filter
	 *            过滤器
	 * @return Query
	 */
	private Query getFilterQuery(SearchFilter filter) {
		BooleanQuery bq = new BooleanQuery();
		for (String f : filter.getFilters()) {
			BooleanQuery tmpBq = new BooleanQuery();
			List<String> valueList = filter.getFilterValue(f);
			for (String value : valueList) {
				tmpBq.add(new TermQuery(new Term(f, value)), Occur.SHOULD);
			}
			bq.add(tmpBq, Occur.MUST);
		}

		return bq;
	}

	private Query getStrategyQuery(List<ISearchStrategy> strategies,
			SearchKeyword keyword, String sorter) {
		BooleanQuery bq = new BooleanQuery();
		int i = strategies.size();
		for (ISearchStrategy strategy : strategies) {
			String word = keyword.getKeyword(strategy.getKeywordField());

			Query query = (Query) strategy
					.getQuery(word, sorter, getBoost(i--));
			if (query != null) {
				bq.add(query, Occur.SHOULD);
			}
		}

		// 添加活动的请求，权重最大
		SameSearchStrategy sss = new SameSearchStrategy();
		sss.setFieldName(IDocumentBuilder.ACTIVITY_FIELD);
		if (keyword.getKeyword() != null) {
			Query query = (Query) sss.getQuery(keyword.getKeyword(), sorter,
					getBoost(strategies.size() + 2));

			bq.add(query, Occur.SHOULD);
		}

		return bq;
	}

	private float getBoost(int value) {
		return SCORE_FACTOR * value;
	}

	@Override
	public String getSearcherName() {
		return searchName;
	}

	public void setSearcherName(String searcherName) {
		this.searchName = searcherName;
	}

	public ISearcherProvider getSearcherProvider() {
		return provider;
	}

	@Override
	public void setSearcherProvider(ISearcherProvider searcherProvider) {
		this.provider = searcherProvider;
	}

	@Override
	public SearchResult nakeSearch(SearchRequest request)
			throws SearchException {
		SearchResult result = new SearchResult();

		Searcher searcher = ((LuceneSearcherInfo) provider.getSearcherInfo()
				.getSearcher()).getSearcher();
		System.out.println(provider.getSearcherInfo().getKey());
		searcher.setSimilarity(new LayerSimilarity());
		try {
			int start = request.getNumberPerPage()
					* (request.getPageNumber() - 1);
			int end = start + request.getNumberPerPage();

			long stime = System.currentTimeMillis();
			BooleanQuery bqall = new BooleanQuery();
			BooleanQuery bq = (BooleanQuery) getStrategyQuery(info
					.getStrategyList(), request.getSearchKeyword(), request
					.getSorter());
			//reamy增加的
			bqall.add(bq, Occur.MUST);
			if (request.getSearchFilter() != null
					&& request.getSearchFilter().size() > 0) {
				//bq.add(getFilterQuery(request.getSearchFilter()), Occur.MUST);
				//reamy修改
				bqall.add(getFilterQuery(request.getSearchFilter()), Occur.MUST);
			}

			//TopDocs tds = searcher.search(bq, end);
			//reamy修改
			TopDocs tds = searcher.search(bqall, end);
			end = Math.min(tds.totalHits, end);

			long etime = System.currentTimeMillis();

			result.addProperty(LENGTH, String.valueOf(tds.totalHits));

			List<ResultInfo> resultInfoList = null;
			// IRecordScorer score = info.getScorer(request.getSorter());
			// if (score == null) {
			// resultInfoList = new ArrayList<ResultInfo>();
			// EventLogger.error("没有指定搜索的排序机制", LilyMonitor.getSearcherKey());
			// } else {
			// resultInfoList = BlockResultUtil.getResultInfos(score, request,
			// tds, searcher, info);
			//
			// }
			resultInfoList = getResultInfoList(start, end, tds.scoreDocs,
					searcher, request.getKeyword());

			result.addProperty(TIME, String.valueOf(etime - stime));

			for (ResultInfo info : resultInfoList) {
				result.addSearchInfo(info);
			}

		} catch (Exception e) {
			e.printStackTrace();
			System.out.println(e.getMessage());
			throw new SearchException(ExceptionUtil.getExceptionContent(e));
		}

		return result;
	}
}
